package city.spring.modules.work.service.impl;

import city.spring.modules.work.entity.WorkScheduleEntity;
import city.spring.modules.work.entity.WorkScheduleItemEntity;
import city.spring.modules.work.entity.WorkScheduleShiftEntity;
import city.spring.modules.work.repository.WorkScheduleItemRepository;
import city.spring.modules.work.repository.WorkScheduleRepository;
import city.spring.modules.work.service.GenerateWorkScheduleService;
import city.spring.modules.work.service.WorkScheduleItemService;
import city.spring.modules.work.service.WorkScheduleService;
import city.spring.modules.work.service.WorkScheduleShiftService;
import city.spring.modules.work.vo.WorkScheduleItemVO;
import city.spring.modules.work.vo.WorkScheduleVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ArrayListMultimap;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

/**
 * Service：上班计划表（排班结果主体记录）
 *
 * @author 侯坤林
 * @date 2020-06-04 16:43:43
 */
@CacheConfig(cacheNames = {WorkScheduleServiceImpl.CACHE_NAME})
@Transactional(rollbackFor = Throwable.class)
@Service
public class WorkScheduleServiceImpl extends ServiceImpl<WorkScheduleRepository, WorkScheduleEntity> implements WorkScheduleService {
    private final GenerateWorkScheduleService generateWorkScheduleService;
    private final WorkScheduleItemService scheduleItemService;
    private final WorkScheduleShiftService scheduleShiftService;
    private final WorkScheduleItemRepository scheduleItemRepository;

    public WorkScheduleServiceImpl(GenerateWorkScheduleService generateWorkScheduleService, WorkScheduleItemService scheduleItemService, WorkScheduleShiftService scheduleShiftService) {
        this.generateWorkScheduleService = generateWorkScheduleService;
        this.scheduleItemService = scheduleItemService;
        this.scheduleShiftService = scheduleShiftService;
        this.scheduleItemRepository = (WorkScheduleItemRepository) scheduleItemService.getBaseMapper();
    }

    @Override
    public void saveWorkSchedule(WorkScheduleEntity entity) {
        if (!save(entity)) {
            throw new RuntimeException("保存信息失败");
        }
        generateWorkScheduleService.generateSchedule(entity);
    }

    @Override
    public void updateWorkSchedule(WorkScheduleEntity entity) {
        // 使用 updateById(entity); 修改数据时，将会修改 entity 对象中所有非null数据，如果某个字段为null，将会忽略该字段的修改
        boolean update = updateById(entity);
        if (!update) {
            throw new RuntimeException("修改信息失败");
        }
    }

    @Override
    public void deleteWorkSchedule(String primaryKey) {
        removeById(primaryKey);
        scheduleItemService.lambdaUpdate().eq(WorkScheduleItemEntity::getWorkScheduleId, primaryKey).remove();
        scheduleShiftService.lambdaUpdate().eq(WorkScheduleShiftEntity::getWorkScheduleId, primaryKey).remove();
    }

    @Override
    public void deleteWorkSchedule(List<String> primaryKeys) {
        removeByIds(primaryKeys);
        scheduleItemService.lambdaUpdate()
                .in(!primaryKeys.isEmpty(), WorkScheduleItemEntity::getWorkScheduleId, primaryKeys).remove();
        scheduleShiftService.lambdaUpdate()
                .in(!primaryKeys.isEmpty(), WorkScheduleShiftEntity::getWorkScheduleId, primaryKeys).remove();
    }

    @Override
    public WorkScheduleVO getWorkSchedule(String primaryKey) {
        WorkScheduleEntity scheduleEntity = getById(primaryKey);
        if (scheduleEntity == null) {
            return null;
        }
        WorkScheduleVO scheduleVO = new WorkScheduleVO(scheduleEntity);
        scheduleVO.setItems(scheduleItemRepository.getScheduleItems(primaryKey, true));
        scheduleVO.setShifts(scheduleShiftService.getScheduleShifts(primaryKey));
        return scheduleVO;
    }

    @Override
    public List<WorkScheduleEntity> getDayWorkSchedules(LocalDate date, Boolean enabled) {
        LocalDate nextDate = date.plusDays(15);
        BiConsumer<LambdaQueryWrapper<WorkScheduleEntity>, LocalDate> confirmCallback = (wrapper, value) -> {
            wrapper.le(WorkScheduleEntity::getStartDate, value).ge(WorkScheduleEntity::getEndDate, value);
        };
        return lambdaQuery()
                .eq(enabled != null, WorkScheduleEntity::getIsEnabled, enabled)
                .and(wrapper -> {
                    // 获取当前时间的排班表主体
                    wrapper.and(wrapper1 -> confirmCallback.accept(wrapper1, date));
                    // 获取未来第15天所在的日期的排班表主体
                    wrapper.or(wrapper1 -> confirmCallback.accept(wrapper1, nextDate));
                })
                .list();
    }

    @Override
    public List<WorkScheduleVO> getUserWorkSchedule(String userId, LocalDate date, boolean history) {
        // 具体的排班记录列表
        List<WorkScheduleItemVO> items;
        // 排班记录对应的排班结果对象列表
        List<WorkScheduleEntity> scheduleEntityList;

        // 查询到这些主体值班表中当前登录用户的值班信息
        LambdaQueryWrapper<? extends WorkScheduleItemEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(WorkScheduleItemEntity::getUserId, userId);
        wrapper.apply("t1.is_enabled = {0}", true);
        if (history) {
            // 直接加载所有当前用户的列表
            items = scheduleItemRepository.getItems(wrapper);
            Set<String> scheduleIds = items.stream()
                    .map(WorkScheduleItemEntity::getWorkScheduleId)
                    .collect(Collectors.toSet());
            // 加载排班表主体信息
            if (scheduleIds.isEmpty()) {
                scheduleEntityList = new ArrayList<>();
            } else {
                scheduleEntityList = lambdaQuery()
                        .in(WorkScheduleEntity::getId, scheduleIds)
                        .eq(WorkScheduleEntity::getIsEnabled, true)
                        .list();
            }
        } else {
            if (date == null) {
                date = LocalDate.now();
            }
            // 查询到当日已启用的所有值班表主体信息
            scheduleEntityList = getDayWorkSchedules(date, true);
            Set<String> scheduleIds = scheduleEntityList.stream()
                    .map(WorkScheduleEntity::getId)
                    .collect(Collectors.toSet());
            if (scheduleIds.isEmpty()) {
                // 返回一个空列表
                items = new ArrayList<>();
            } else {
                // 加载当前的值班表
                wrapper.in(WorkScheduleItemEntity::getWorkScheduleId, scheduleIds);

                items = scheduleItemRepository.getItems(wrapper);
            }
        }

        // 处理当前登录用户的值班信息
        List<WorkScheduleVO> result = new ArrayList<>();
        ArrayListMultimap<String, WorkScheduleItemVO> multimap = ArrayListMultimap.create();
        for (WorkScheduleItemVO item : items) {
            multimap.put(item.getWorkScheduleId(), item);
        }
        for (WorkScheduleEntity scheduleEntity : scheduleEntityList) {
            String key = scheduleEntity.getId();
            // 只返回存在值班记录的值班主体信息和值班记录信息
            if (multimap.containsKey(key)) {
                WorkScheduleVO scheduleVO = new WorkScheduleVO(scheduleEntity);
                scheduleVO.setItems(multimap.get(key));
                scheduleVO.setShifts(scheduleShiftService.getScheduleShifts(scheduleEntity.getId()));

                result.add(scheduleVO);
            }
        }
        return result;
    }
}